﻿using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Threading;
using System.Threading.Tasks;

namespace Isuka.Automation
{
    /// <summary>
    /// オートメーションオブジェクトツリーの根となるオブジェクト
    /// </summary>
    public abstract class AutomationRootObject
        : AutomationObject
    {
        readonly Container container = new Container();

        protected AutomationRootObject(string progId)
            : base(ComObjectFactory.CreateObject(progId))
        {
            Contract.Requires(!String.IsNullOrEmpty(progId));
        }

        protected AutomationRootObject(object rootObject)
            : base(rootObject)
        {
            Contract.Requires<ArgumentNullException>(rootObject != null);
        }

        public IContainer Container
        {
            get
            {
                Contract.Ensures(Contract.Result<IContainer>() != null);
                return container;
            }
        }

        protected override void PreReleaseObject()
        {
            container.Dispose();
        }

        protected override void ReleaseObject(object obj)
        {
            // オブジェクトを開放する
            base.ReleaseObject(obj);

            // 最後にGCを動かす
            Task.Factory.StartNew(() =>
            {
                GC.WaitForFullGCComplete();
                GC.Collect();
                GC.WaitForFullGCComplete();
                GC.Collect();
            });
        }

        #region ContractInvariantMethod

        [ContractInvariantMethod]
        [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Required for code contracts.")]
        void ObjectInvariant()
        {
            Contract.Invariant(container != null);
        }

        #endregion
    }
}
